#include "animation.h"

Animation::Animation(Card *card, const QPointF &target, int duration, tweeny::easing::enumerated easing, QObject *parent)
    : QObject{parent}
{
    tween_ = tweeny::from(card->pos().x(), card->pos().y()).to(target.x(), target.y())
                    .during(duration / (1000/ 60.0)).via(easing)
                    .onStep([card](double x, double y){
                        card->setPos(QPointF(x, y));
                        return false;
                    });
    card_ = card;
    sound_effect = nullptr;
    flip_before_start = false;
    z_value = -1;
    is_finished = false;
}

void Animation::step()
{
    if (is_finished) return;
    if (tween_.progress() < 0.00001f)
    {
        if (z_value != -1)
        {
            card_->setZValue(z_value);
        }
        if (flip_before_start)
        {
            card_->flip();
        }
        if (sound_effect != nullptr)
        {
            sound_effect->play();
        }
    }
    tween_.step(1);
    if (tween_.progress() >= 1.0f)
    {
        is_finished = true;
        emit finished();
    }
}

AnimationGroup::~AnimationGroup()
{
    for (int i = 0; i < animations.size(); ++i)
    {
        animations[i]->deleteLater();
    }
}

void AnimationGroup::step()
{
    if (active_animations.empty()) return;
    for (int i = 0; i < active_animations.size(); ++i)
    {
        active_animations[i]->step();
    }
    active_animations.erase(std::remove_if(active_animations.begin(), active_animations.end(),
                                           [](Animation *anim) { return anim->isFinished();}),
                            active_animations.end());
}

ParallelAnimationGroup::ParallelAnimationGroup(QObject *parent)
    : AnimationGroup{parent}, delay(0), current(0)
{
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &ParallelAnimationGroup::slotTimeout);
}

void ParallelAnimationGroup::slotTimeout()
{
    if (current < animations.size())
    {
        active_animations.push_back(animations[current++]);
    }
    if (current == animations.size())
    {
        timer->stop();
    }
}

void ParallelAnimationGroup::step()
{

    if (!started)
    {
        if (animations.empty()) return;
        connect(animations.back(), &Animation::finished, this, &ParallelAnimationGroup::finished);
        if (delay > 0)
        {
            timer->start(delay);
        }
        else
        {
            for (int i = 0; i < animations.size(); ++i)
            {
                active_animations.push_back(animations[i]);
            }
        }
        started = true;
    }
    AnimationGroup::step();
}

void SequentialAnimationGroup::step()
{
    if (!started)
    {
        if (animations.empty()) return;
        connect(animations.back(), &Animation::finished, this, &SequentialAnimationGroup::finished);
        active_animations.push_back(animations[current++]);
        started = true;
    }
    AnimationGroup::step();
    if (active_animations.empty() && current < animations.size())
    {
        active_animations.push_back(animations[current++]);
    }
}
